module Hotel (Hotel, sobreReservadoH, huespedesConPalabraH, nuevoH, nombreH, cadenaH, ingresosH, salidasH, huespedesH, reservasH, tarifaXDiaH, precioAccesorioH, registrarHuespedH, desregistrarHuespedH, hacerReservaH, calcularCuentaH, reservasSolapadasH, venderH, habitacionesH) where

import Tipos
import Habitacion
import Reserva
import List

data Hotel = HT Nombre Cadena [Habitacion] [(TipoHabitacion, Dinero)] [(Accesorio, Dinero)] | CI DNI Fecha Habitacion Hotel | CO DNI Fecha Hotel | R Reserva Hotel deriving (Show, Eq)

nuevoH :: Nombre -> Cadena -> [Habitacion] -> [(TipoHabitacion, Dinero)] -> [(Accesorio, Dinero)] -> Hotel
nuevoH n c hs txd ad = HT n c hs txd ad

nombreH :: Hotel -> Nombre
nombreH (HT n _ _ _ _) = n
nombreH (CI _ _ _ ht) = nombreH ht
nombreH (CO _ _ ht) = nombreH ht
nombreH (R _ ht) = nombreH ht

cadenaH :: Hotel -> Cadena
cadenaH (HT _ c _ _ _) = c
cadenaH (CI _ _ _ ht) = cadenaH ht
cadenaH (CO _ _ ht) = cadenaH ht
cadenaH (R _ ht) = cadenaH ht

huespedesH :: Hotel -> [DNI]
huespedesH (HT _ _ _ _ _) = []
huespedesH (CI d f hb ht) = d : (huespedesH ht)
huespedesH (CO d f ht) = quitarHuesped d f (huespedesH ht) 
huespedesH (R _ h) = huespedesH h

habitacionesH :: Hotel -> [Habitacion]
habitacionesH (HT _ _ hs _ _) = hs
habitacionesH (CI _ _ _ ht) = habitacionesH ht
habitacionesH (CO _ _ ht) = habitacionesH ht
habitacionesH (R _ ht) = habitacionesH ht

ingresosH :: Hotel -> [(CheckIn, Habitacion)] 
ingresosH (HT _ _ _ _ _) = []
ingresosH (CI dni fecha hab h) = ((dni, fecha), hab):ingresosH(h)
ingresosH (CO _ _  h) = ingresosH h
ingresosH (R res h) = ingresosH h

salidasH :: Hotel -> [CheckOut]
salidasH (HT _ _ _ _ _) = []
salidasH (CI _ _ _ h) = salidasH h
salidasH (R _ h) = salidasH h
salidasH (CO x y h) = (x, y):salidasH h

reservasH :: Hotel -> [Reserva]
reservasH (HT _ _ _ _ _) = []
reservasH (CI _ _ _ h) = reservasH h
reservasH (CO _ _ h) = reservasH h
reservasH (R x h) = (x:reservasH h)

tarifaXDiaH :: Hotel -> TipoHabitacion -> Dinero
tarifaXDiaH (HT _ _ _ xs _) t = tarifaAux xs t
tarifaXDiaH (CI _ _ _ h) t = tarifaXDiaH h t
tarifaXDiaH (CO _ _ h) t = tarifaXDiaH h t
tarifaXDiaH (R _ h) t = tarifaXDiaH h t

precioAccesorioH :: Hotel -> Accesorio -> Dinero
precioAccesorioH (HT _ _ _ _ as) a = precioAccAux as a
precioAccesorioH (CI _ _ _ h) a = precioAccesorioH h a
precioAccesorioH (CO _ _ h) a = precioAccesorioH h a
precioAccesorioH (R _ h) a = precioAccesorioH h a

venderH :: Hotel -> Cadena -> Hotel
venderH (HT n _ hs ts as) c = HT n c hs ts as
venderH (CI dni fecha hab h) c = CI dni fecha hab (venderH h c)
venderH (CO d f h) c = CO d f (venderH h c)
venderH (R res h) c = R res (venderH h c)

hacerReservaH :: Hotel -> Reserva -> Hotel
hacerReservaH h res = R res h

sobreReservadoH :: Hotel -> Fecha -> Bool
sobreReservadoH h fecha = capacidad h < plazasReservadasH h fecha

registrarHuespedH :: Hotel -> DNI -> Fecha -> Habitacion -> Hotel
registrarHuespedH (HT n c hs ts as) dni fecha hab = HT n c hs ts as
registrarHuespedH (CI x y z h) dni fecha hab = (CI x y z (registrarHuespedH h dni fecha hab))
registrarHuespedH (CO x y h) dni fecha hab = (CO x y (registrarHuespedH h dni fecha hab))
registrarHuespedH (R res h) dni fecha hab
  | ((documentoR res) == dni) && ((fechaDesdeR res) == fecha) = CI dni fecha hab (R (confirmarR res) (registrarHuespedH h dni fecha hab))
  | otherwise = R res (registrarHuespedH h dni fecha hab)


desregistrarHuespedH :: Hotel -> DNI -> Fecha -> Hotel
desregistrarHuespedH (HT n c hs ts as) dni fecha = HT n c hs ts as
desregistrarHuespedH (CO x y h) dni fecha = CO x y (desregistrarHuespedH h dni fecha)
desregistrarHuespedH (R res h) dni fecha = R res (desregistrarHuespedH h dni fecha)
desregistrarHuespedH (CI x y z h) dni fecha
                |x==dni = CO dni fecha (CI x y z h)
                |otherwise= CI x y z (desregistrarHuespedH h dni fecha)

huespedesConPalabraH :: Hotel -> [DNI]
huespedesConPalabraH h = sacarRepetidos (huesConPalabraAux2 h h)

calcularCuentaH :: Hotel -> CheckIn -> CheckOut -> Habitacion -> Dinero
calcularCuentaH h ci co hab = ((tarifaXDiaH h (tipoH hab)) * ((snd co) - (snd ci))) + (precioAccs h (accesoriosH hab))

reservasSolapadasH :: Hotel -> DNI -> Bool
reservasSolapadasH (HT _ _ _ _ _) dni = False
reservasSolapadasH (CO _ _  h) dni = reservasSolapadasH h dni
reservasSolapadasH (CI _ _ _ h) dni = reservasSolapadasH h dni
reservasSolapadasH (R res h) dni
  | documentoR res == dni && seSolapa h res= True 
  | otherwise = reservasSolapadasH h dni

----------------
-- Auxiliares --
----------------

precioTipoHab :: Hotel -> TipoHabitacion -> Dinero
precioTipoHab (HT _ _ _ xs _) t = precioTipoHabAux xs t
precioTipoHab (CI _ _ _ h) t = precioTipoHab h t
precioTipoHab (CO _ _ h) t = precioTipoHab h t
precioTipoHab (R _ h) t = precioTipoHab h t

precioTipoHabAux :: [(TipoHabitacion, Dinero)] -> TipoHabitacion -> Dinero
precioTipoHabAux (x:[]) t
  | fst x == t = snd x
precioTipoHabAux (x:xs) t
  | fst x == t = snd x
  | otherwise = precioTipoHabAux xs t

tarifaAux:: [(TipoHabitacion, Dinero)] -> TipoHabitacion -> Dinero
tarifaAux [] _ = 0
tarifaAux (t:ts) x
  | fst t == x = snd t
  | otherwise  = tarifaAux ts x 

precioAccAux:: [(Accesorio, Dinero)] -> Accesorio -> Dinero
precioAccAux [] _ = 0
precioAccAux (a:as) acc
  | fst a == acc = snd a
  | otherwise = precioAccAux as acc

-- calcularCuentaH --

precioAccs:: Hotel -> [Accesorio] -> Dinero
precioAccs h (a:[]) = precioAccesorioH h a --precioDeUnAccesorio h (precioAccesorioH h a) a
precioAccs h (a:as) = precioAccesorioH h a + precioAccs h as --precioDeUnAccesorio h (precioAccesorioH h a) a + (precioAccs h as)

precioDeUnAccesorio :: Hotel -> [(Accesorio, Dinero)] -> Accesorio -> Dinero
precioDeUnAccesorio h (a:as) x 
  | fst a == x = snd a
  | otherwise = precioDeUnAccesorio h as x
                                                     
-- sobreReservadoH --

capacidad :: Hotel -> Int
capacidad (HT _ _  hs ts as) = sumacap hs 
capacidad (CI _ _ _ h) = capacidad h
capacidad (CO _ _ h) = capacidad h
capacidad (R _ h) = capacidad h

sumacap :: [Habitacion] -> Int
sumacap [] = 0
sumacap (h:hs) = (cantidadHuespedes (tipoH h) ) + sumacap(hs)

plazasReservadasH:: Hotel -> Fecha -> Int
plazasReservadasH (HT _ _ _ _ _) f = 0
plazasReservadasH (CI _ _ _ h) f = plazasReservadasH h f
plazasReservadasH (CO _ _ h) f = plazasReservadasH  h f
plazasReservadasH (R res h) f
  |fechaDesdeR res  <= f && f <= fechaHastaR res  = cantidadHuespedes(tipoR res ) + (plazasReservadasH h f)
  |otherwise = plazasReservadasH h f

cantidadHuespedes :: TipoHabitacion -> Int
cantidadHuespedes t
  | t == Simple     = 1
  | t == Doble      = 2
  | t == Triple     = 3
  | t == Cuadruple  = 4 
  
-- HuespedesConPalabra --

huesConPalabraAux2 :: Hotel -> Hotel -> [DNI]
huesConPalabraAux2 (HT _ _ _ _ _) ho = []
huesConPalabraAux2 (CO _ _ h) ho = huesConPalabraAux2 h ho
huesConPalabraAux2 (R res h) ho = huesConPalabraAux2 h ho
huesConPalabraAux2 (CI d f _ h) ho
  | hayReserva h ho d f = d : huesConPalabraAux2 h ho
  | otherwise = huesConPalabraAux2 h ho

hayReserva:: Hotel -> Hotel  -> DNI -> Fecha -> Bool
hayReserva (HT _ _ _ _ _) d f ho = False
hayReserva (CI _ _ _ h) d f ho = hayReserva h d f ho
hayReserva (CO _ _ h) d f ho = hayReserva h d f ho
hayReserva (R r h) ho d f = d == documentoR r && f == fechaDesdeR r && (siguienteCheckOutFecha ho d f) == fechaHastaR r && confirmadaR r

siguienteCheckOutFecha:: Hotel -> DNI -> Fecha -> Fecha
siguienteCheckOutFecha (HT _ _ _ _ _) d f= 0
siguienteCheckOutFecha (R _ h) d f = siguienteCheckOutFecha h d f
siguienteCheckOutFecha (CI _ _ _ h) d f = siguienteCheckOutFecha h d f
siguienteCheckOutFecha (CO x y h) d f
  |x==d && (elProximoCheckInTieneFecha h d f) = y
  |otherwise= siguienteCheckOutFecha h d f


elProximoCheckInTieneFecha:: Hotel -> DNI -> Fecha -> Bool
elProximoCheckInTieneFecha (R r h) d f = elProximoCheckInTieneFecha h d f
elProximoCheckInTieneFecha (CO _ _ h) d f= elProximoCheckInTieneFecha h d f
elProximoCheckInTieneFecha (HT _ _ _ _ _) d f = False
elProximoCheckInTieneFecha (CI x y hab h) d f
  |x==d && y == f = True
  |x==d && y /= f = False
  |otherwise = elProximoCheckInTieneFecha h d f

-- huespedesH --

quitarHuesped :: DNI -> Fecha -> [DNI] -> [DNI]
quitarHuesped d f (x:[])
  | d == x = []
  | otherwise = [x]
quitarHuesped d f (x:xs)
  | d == x = quitarHuesped d f xs
  | otherwise = x:(quitarHuesped d f xs)

-- reservasSolapadasH--

seSolapa:: Hotel -> Reserva -> Bool
seSolapa (HT _ _ _ _ _) res = False
seSolapa (CI _ _ _ h) res = seSolapa h res
seSolapa (CO _ _ h) res = seSolapa h res
seSolapa (R r h) res
  |documentoR(r) == documentoR(res) && (fechaDesdeR(res) <= fechaDesdeR(r) && fechaDesdeR(res) <= fechaHastaR(r)) = True
  |documentoR(r) == documentoR(res) && (fechaDesdeR(res) <= fechaHastaR(r) && fechaHastaR(res) <= fechaHastaR(r)) = True
  |otherwise = seSolapa h res 

-- desregistrarHuespedH --

sacarRepetidos :: [DNI] -> [DNI]
sacarRepetidos [] = []
sacarRepetidos (x:[]) = [x]
sacarRepetidos (x:xs)
  | elem x xs = sacarRepetidos xs
  | otherwise = x:(sacarRepetidos xs)
